#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
校准数据读取器
为其他程序提供访问和使用校准数据的便捷接口
"""

import json
import os
from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime

# 可选导入numpy
try:
    import numpy as np
    HAS_NUMPY = True
except ImportError:
    np = None
    HAS_NUMPY = False


class CalibrationDataReader:
    """校准数据读取和访问类

    提供便捷的接口来读取、查询和分析衰减器校准数据
    """

    def __init__(self, data_file_path: str = "calibration_data.json"):
        """初始化校准数据读取器

        Args:
            data_file_path: 校准数据文件路径
        """
        self.data_file_path = data_file_path
        self.calibration_data = {}
        self.metadata = {}
        self._load_data()

    def _load_data(self) -> bool:
        """加载校准数据文件

        Returns:
            bool: 加载是否成功
        """
        try:
            if not os.path.exists(self.data_file_path):
                print(f"警告: 校准数据文件不存在: {self.data_file_path}")
                return False

            with open(self.data_file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)

            # 解析数据结构
            if isinstance(data, dict):
                # 旧格式：直接是校准数据
                raw_data = data
                self.metadata = {}

                # 标准化键格式
                self.calibration_data = {}
                for setting_key, freq_data in raw_data.items():
                    # 标准化设置值键
                    normalized_setting = float(setting_key)
                    self.calibration_data[normalized_setting] = {}

                    # 标准化频率值键
                    for freq_key, att_value in freq_data.items():
                        normalized_freq = float(freq_key)
                        self.calibration_data[normalized_setting][normalized_freq] = att_value

            print(f"✅ 成功加载校准数据文件: {self.data_file_path}")
            print(f"📊 衰减设置数量: {len(self.calibration_data)}")

            # 统计频率点数
            total_freq_points = sum(len(freq_data) for freq_data in self.calibration_data.values())
            print(f"📏 总频率点数: {total_freq_points}")

            return True

        except Exception as e:
            print(f"❌ 加载校准数据失败: {str(e)}")
            return False

    def reload_data(self) -> bool:
        """重新加载校准数据"""
        return self._load_data()

    def is_data_available(self) -> bool:
        """检查校准数据是否可用"""
        return bool(self.calibration_data)

    def get_attenuation_settings(self) -> List[float]:
        """获取所有可用的衰减设置值

        Returns:
            List[float]: 排序后的衰减设置列表
        """
        if not self.calibration_data:
            return []

        settings = [float(setting) for setting in self.calibration_data.keys()]
        return sorted(settings)

    def get_frequencies(self, attenuation_setting: float) -> List[float]:
        """获取指定衰减设置下的所有频率点

        Args:
            attenuation_setting: 衰减设置值

        Returns:
            List[float]: 排序后的频率列表
        """
        setting_key = str(attenuation_setting)
        if setting_key not in self.calibration_data:
            return []

        frequencies = [float(freq) for freq in self.calibration_data[setting_key].keys()]
        return sorted(frequencies)

    def get_all_frequencies(self) -> List[float]:
        """获取所有频率点（去重后）

        Returns:
            List[float]: 排序后的所有频率列表
        """
        all_freqs = set()
        for freq_data in self.calibration_data.values():
            all_freqs.update(float(freq) for freq in freq_data.keys())

        return sorted(list(all_freqs))

    def get_attenuation(self, setting: float, frequency: float) -> Optional[float]:
        """获取指定设置和频率下的实际衰减值

        Args:
            setting: 衰减器设置值
            frequency: 频率 (MHz)

        Returns:
            Optional[float]: 实际衰减值，如果不存在则返回None
        """
        setting_key = str(setting)
        freq_key = str(frequency)

        if setting_key in self.calibration_data:
            if freq_key in self.calibration_data[setting_key]:
                return float(self.calibration_data[setting_key][freq_key])

        return None

    def get_frequency_with_interpolation(self, frequency: float) -> Optional[float]:
        frequencies = list(self.calibration_data.keys())
        # 找到最接近的频率
        closest_freq = min(frequencies, key=lambda x: abs(x - frequency))
        return closest_freq

    def get_attenuation_with_interpolation(self, target_att: float, frequency: float) -> Optional[float]:
        """通过插值获取衰减值（当精确频率点不存在时）

        Args:
            setting: 衰减器设置值
            frequency: 频率 (MHz)

        Returns:
            Optional[float]: 插值得到的衰减值
        """
        settings = self.calibration_data[frequency]
        # atts = list(self.calibration_data[frequency].values())
        # 获取最接近的衰减值
        close_setting, att = min(settings.items(), key=lambda x: abs(x[1] - target_att))
        error = abs(target_att) - att
        close_setting = close_setting + error
        close_setting = round(close_setting, 2)
        return close_setting

    def get_zero_attenuation(self, frequency: float) -> Optional[float]:
        """获取指定频率下的零衰减设置值

        Args:
            frequency: 频率 (MHz)

        Returns:
            Optional[float]: 零衰减设置值
        """
        settings = self.calibration_data[frequency]
        return settings[0]

    def get_attenuation_error(self, setting: float, frequency: float) -> Optional[float]:
        """计算衰减误差（实际衰减值 - 设置值）

        Args:
            setting: 衰减器设置值
            frequency: 频率 (MHz)

        Returns:
            Optional[float]: 衰减误差值
        """
        actual_attenuation = self.get_attenuation(setting, frequency)
        if actual_attenuation is not None:
            return actual_attenuation - setting
        return None

    def get_frequency_response(self, setting: float) -> Dict[float, float]:
        """获取指定衰减设置下的频率响应

        Args:
            setting: 衰减器设置值

        Returns:
            Dict[float, float]: 频率 -> 实际衰减值的映射
        """
        setting_key = str(setting)
        if setting_key not in self.calibration_data:
            return {}

        response = {}
        for freq_key, att_value in self.calibration_data[setting_key].items():
            response[float(freq_key)] = float(att_value)

        return response

    def get_attenuation_curve(self, frequency: float) -> Dict[float, float]:
        """获取指定频率下的衰减特性曲线

        Args:
            frequency: 频率 (MHz)

        Returns:
            Dict[float, float]: 设置值 -> 实际衰减值的映射
        """
        freq_key = str(frequency)
        curve = {}

        for setting_key, freq_data in self.calibration_data.items():
            if freq_key in freq_data:
                curve[float(setting_key)] = float(freq_data[freq_key])

        return curve

    def get_statistics(self, setting: Optional[float] = None) -> Dict:
        """获取校准数据统计信息

        Args:
            setting: 指定衰减设置（可选），如果不指定则统计全部数据

        Returns:
            Dict: 统计信息
        """
        stats = {
            'total_settings': len(self.calibration_data),
            'total_frequencies': len(self.get_all_frequencies()),
            'total_data_points': 0,
            'frequency_range': {'min': 0, 'max': 0},
            'attenuation_range': {'min': 0, 'max': 0},
            'metadata': self.metadata
        }

        if not self.calibration_data:
            return stats

        # 统计数据点数
        for freq_data in self.calibration_data.values():
            stats['total_data_points'] += len(freq_data)

        # 频率范围
        all_freqs = self.get_all_frequencies()
        if all_freqs:
            stats['frequency_range']['min'] = min(all_freqs)
            stats['frequency_range']['max'] = max(all_freqs)

        # 衰减设置范围
        settings = self.get_attenuation_settings()
        if settings:
            stats['attenuation_range']['min'] = min(settings)
            stats['attenuation_range']['max'] = max(settings)

        # 如果指定了特定设置
        if setting is not None:
            setting_key = str(setting)
            if setting_key in self.calibration_data:
                freq_data = self.calibration_data[setting_key]
                frequencies = [float(f) for f in freq_data.keys()]
                attenuations = [float(a) for a in freq_data.values()]

                mean_attenuation = sum(attenuations) / len(attenuations) if attenuations else 0

                if HAS_NUMPY and attenuations and np is not None:  # 确保numpy可用
                    std_attenuation = float(np.std(attenuations))
                elif attenuations:
                    # 计算标准差的简单实现
                    variance = sum((x - mean_attenuation) ** 2 for x in attenuations) / len(attenuations)
                    std_attenuation = variance ** 0.5
                else:
                    std_attenuation = 0

                stats['setting_specific'] = {
                    'setting': setting,
                    'frequency_count': len(frequencies),
                    'frequency_range': {'min': min(frequencies), 'max': max(frequencies)} if frequencies else {'min': 0, 'max': 0},
                    'attenuation_range': {'min': min(attenuations), 'max': max(attenuations)} if attenuations else {'min': 0, 'max': 0},
                    'mean_attenuation': mean_attenuation,
                    'std_attenuation': std_attenuation
                }

        return stats

    def export_csv(self, output_path: str, format_type: str = "matrix") -> bool:
        """导出校准数据为CSV格式

        Args:
            output_path: 输出CSV文件路径
            format_type: 导出格式 ("matrix" 或 "list")

        Returns:
            bool: 导出是否成功
        """
        try:
            import csv

            with open(output_path, 'w', newline='', encoding='utf-8-sig') as csvfile:
                if format_type == "matrix":
                    self._export_matrix_format(csvfile)
                else:
                    self._export_list_format(csvfile)

            print(f"✅ 校准数据已导出至: {output_path}")
            return True

        except Exception as e:
            print(f"❌ 导出CSV失败: {str(e)}")
            return False

    def _export_matrix_format(self, csvfile):
        """导出矩阵格式的CSV"""
        import csv

        writer = csv.writer(csvfile)

        # 获取所有频率和设置
        all_frequencies = self.get_all_frequencies()
        all_settings = self.get_attenuation_settings()

        # 写入头部
        header = ['衰减设置(dB)'] + [f'{freq:.1f}MHz' for freq in all_frequencies]
        writer.writerow(header)

        # 写入数据行
        for setting in all_settings:
            row = [f'{setting:.1f}']
            for freq in all_frequencies:
                attenuation = self.get_attenuation(setting, freq)
                row.append(f'{attenuation:.3f}' if attenuation is not None else 'N/A')
            writer.writerow(row)

    def _export_list_format(self, csvfile):
        """导出列表格式的CSV"""
        import csv

        writer = csv.writer(csvfile)

        # 写入头部
        writer.writerow(['衰减设置(dB)', '频率(MHz)', '实际衰减(dB)', '误差(dB)'])

        # 写入数据
        for setting in self.get_attenuation_settings():
            for freq in self.get_frequencies(setting):
                attenuation = self.get_attenuation(setting, freq)
                error = attenuation - setting if attenuation is not None else None

                writer.writerow([
                    f'{setting:.1f}',
                    f'{freq:.1f}',
                    f'{attenuation:.3f}' if attenuation is not None else 'N/A',
                    f'{error:.3f}' if error is not None else 'N/A'
                ])

    def find_closest_calibration_point(self, target_setting: float, target_frequency: float) -> Optional[Tuple[float, float, float]]:
        """查找最接近的校准点

        Args:
            target_setting: 目标衰减设置
            target_frequency: 目标频率

        Returns:
            Optional[Tuple[float, float, float]]: (设置, 频率, 衰减值) 或 None
        """
        min_distance = float('inf')
        closest_point = None

        for setting in self.get_attenuation_settings():
            for frequency in self.get_frequencies(setting):
                distance = abs(setting - target_setting) + abs(frequency - target_frequency) / 1000  # 频率权重较小

                if distance < min_distance:
                    min_distance = distance
                    attenuation = self.get_attenuation(setting, frequency)
                    if attenuation is not None:
                        closest_point = (setting, frequency, attenuation)

        return closest_point


# 使用示例和测试代码
def demo_usage():
    """演示校准数据读取器的使用方法"""
    print("=" * 60)
    print("校准数据读取器使用演示")
    print("=" * 60)

    # 创建读取器实例
    reader = CalibrationDataReader("calibration_data.json")

    if not reader.is_data_available():
        print("❌ 没有可用的校准数据")
        return

    # 基本信息
    print("\n📊 基本信息:")
    settings = reader.get_attenuation_settings()
    frequencies = reader.get_all_frequencies()
    print(f"   衰减设置范围: {min(settings):.1f} - {max(settings):.1f} dB")
    print(f"   频率范围: {min(frequencies):.1f} - {max(frequencies):.1f} MHz")

    # 查询特定值
    print("\n🔍 查询示例:")
    test_setting = 20.0
    test_frequency = 1000.0

    attenuation = reader.get_attenuation(test_setting, test_frequency)
    if attenuation:
        error = attenuation - test_setting
        print(f"   设置: {test_setting}dB, 频率: {test_frequency}MHz")
        print(f"   实际衰减: {attenuation:.3f}dB")
        print(f"   误差: {error:.3f}dB")

    # 插值查询
    interp_attenuation = reader.get_attenuation_with_interpolation(test_setting, 1050.0)
    if interp_attenuation:
        print(f"   插值查询 (1050MHz): {interp_attenuation:.3f}dB")

    # 统计信息
    print("\n📈 统计信息:")
    stats = reader.get_statistics()
    print(f"   总数据点: {stats['total_data_points']}")
    print(f"   设置数量: {stats['total_settings']}")
    print(f"   频率点数: {stats['total_frequencies']}")

    # 导出示例
    print("\n💾 导出示例:")
    if reader.export_csv("calibration_export.csv", "matrix"):
        print("   矩阵格式导出成功")

    if reader.export_csv("calibration_list.csv", "list"):
        print("   列表格式导出成功")


if __name__ == "__main__":
    demo_usage()